package com.ljh.lottery.common.utils;

import cn.hutool.crypto.digest.DigestUtil;
import com.ljh.lottery.common.errorcode.ControllerErrorCodeConstants;
import com.ljh.lottery.common.errorcode.GlobalErrorCodeConstants;
import com.ljh.lottery.common.errorcode.ServiceErrorCodeConstants;
import com.ljh.lottery.common.exception.ControllerException;
import com.ljh.lottery.common.exception.ServiceException;
import com.ljh.lottery.pojo.dataobject.*;
import com.ljh.lottery.pojo.request.*;
import com.ljh.lottery.pojo.response.*;
import com.ljh.lottery.service.dto.*;
import com.ljh.lottery.service.enums.*;
import org.springframework.beans.BeanUtils;

import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @author: Themberfue
 * @date: 2025/4/10 12:33
 * @description:
 */
public class BeanTransUtil {
    /**
     * @return UserDO
     */
    public static UserDO transToUserDO(UserRegisterRequest userRegisterRequest) {
        if (null == userRegisterRequest) {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }
        UserDO userDO = new UserDO();
        BeanUtils.copyProperties(userRegisterRequest, userDO);
        userDO.setPhoneNumber(new Encrypt(userRegisterRequest.getPhoneNumber()));
        userDO.setPassword(DigestUtil.sha256Hex(userRegisterRequest.getPassword()));
        return userDO;
    }

    /**
     * @return UserRegisterDTO
     */
    public static UserRegisterDTO transToUserRegisterDTO(UserDO userDO) {
        if (null == userDO) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_NULL);
        }
        UserRegisterDTO userRegisterDTO = new UserRegisterDTO();
        userRegisterDTO.setUserId(userDO.getId());
        return userRegisterDTO;
    }

    /**
     * @return UserRegisterResponse
     */
    public static UserRegisterResponse transToUserRegisterResponse(UserRegisterDTO userRegisterDTO) {
        if (null == userRegisterDTO) {
            throw new ControllerException(ControllerErrorCodeConstants.REGISTER_ERROR);
        }
        UserRegisterResponse userRegisterResponse = new UserRegisterResponse();
        BeanUtils.copyProperties(userRegisterDTO, userRegisterResponse);
        return userRegisterResponse;
    }

    /**
     * @return UserLoginResponse
     */
    public static UserLoginResponse transToUserLoginResponse(UserLoginDTO userLoginDTO) {
        if (null == userLoginDTO) {
            throw new ControllerException(ControllerErrorCodeConstants.LOGIN_ERROR);
        }
        UserLoginResponse userLoginResponse = new UserLoginResponse();
        BeanUtils.copyProperties(userLoginDTO, userLoginResponse);
        userLoginResponse.setIdentity(userLoginDTO.getIdentity().name());
        return userLoginResponse;
    }

    /**
     * @return BaseUserInfoResponse
     */
    public static BaseUserInfoResponse transToBaseUserInfoResponse(UserDTO userDTO) {
        if (null == userDTO) {
            throw new ControllerException(ControllerErrorCodeConstants.LOGIN_ERROR);
        }
        BaseUserInfoResponse baseUserInfoResponse = new BaseUserInfoResponse();
        BeanUtils.copyProperties(userDTO, baseUserInfoResponse);
        baseUserInfoResponse.setIdentity(userDTO.getIdentity().name());
        return baseUserInfoResponse;
    }

    /**
     * @return UserDTO
     */
    public static UserDTO transToUserDTO(UserDO userDO) {
        if (null == userDO) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_NULL);
        }
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(userDO, userDTO);
        userDTO.setUserId(userDO.getId());
        userDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
        userDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userDTO;
    }

    /**
     * @return PrizeDO
     */
    public static PrizeDO transToPrizeDO(CreatePrizeRequest createPrizeRequest, String fileName) {
        if (null == createPrizeRequest) {
            throw new ServiceException(ServiceErrorCodeConstants.PRIZE_INFO_IS_NULL);
        }
        if (null == fileName) {
            throw new ServiceException(ServiceErrorCodeConstants.PIC_UPLOAD_ERROR);
        }
        PrizeDO prizeDO = new PrizeDO();
        BeanUtils.copyProperties(createPrizeRequest, prizeDO);
        prizeDO.setName(createPrizeRequest.getPrizeName());
        prizeDO.setImageUrl(fileName);
        return prizeDO;
    }

    /**
     * @return PrizeListResponse
     */
    public static PrizeListResponse transToPrizeListResponse(PageListDTO<PrizeDTO> pageListDTO) {
        if (null == pageListDTO) {
            throw new ControllerException(ControllerErrorCodeConstants.GET_PRIZE_LIST_ERROR);
        }
        PrizeListResponse prizeListResponse = new PrizeListResponse();
        prizeListResponse.setTotal(pageListDTO.getTotal());
        prizeListResponse.setRecords(pageListDTO.getRecords()
                .stream()
                .map(BeanTransUtil::transToPrizeInfo)
                .toList());
        return prizeListResponse;
    }

    /**
     * @return PrizeListResponse.PrizeInfo
     */
    private static PrizeListResponse.PrizeInfo transToPrizeInfo(PrizeDTO prizeDTO) {
        if (null == prizeDTO) {
            throw new ControllerException(ControllerErrorCodeConstants.GET_PRIZE_LIST_ERROR);
        }
        PrizeListResponse.PrizeInfo prizeInfo = new PrizeListResponse.PrizeInfo();
        BeanUtils.copyProperties(prizeDTO, prizeInfo);
        prizeInfo.setPrizeName(prizeDTO.getName());
        return prizeInfo;
    }

    /**
     * @return PrizeDTO
     */
    public static PrizeDTO transToPrizeDTO(PrizeDO prizeDO) {
        if (null == prizeDO) {
            throw new ServiceException(ServiceErrorCodeConstants.GET_PRIZE_LIST_ERROR);
        }
        PrizeDTO prizeDTO = new PrizeDTO();
        BeanUtils.copyProperties(prizeDO, prizeDTO);
        prizeDTO.setPrizeId(prizeDO.getId());
        return prizeDTO;
    }

    /**
     * @return CreateActivityResponse
     */
    public static CreateActivityResponse tansToCreateActivityResponse(CreateActivityDTO activity) {
        if (null == activity) {
            throw new ControllerException(ControllerErrorCodeConstants.CREATE_ACTIVITY_ERROR);
        }
        CreateActivityResponse createActivityResponse = new CreateActivityResponse();
        BeanUtils.copyProperties(activity, createActivityResponse);
        return createActivityResponse;
    }

    /**
     * @return ActivityDO
     */
    public static ActivityDO transToActivityDO(CreateActivityRequest param) {
        if (null == param) {
            throw new ServiceException(ServiceErrorCodeConstants.CREATE_ACTIVITY_INFO_IS_EMPTY);
        }
        ActivityDO activityDO = new ActivityDO();
        BeanUtils.copyProperties(param, activityDO);
        activityDO.setStatus(ActivityStatusEnum.RUNNING.name());
        return activityDO;
    }

    /**
     * @return ActivityPrizeDO
     */
    public static ActivityPrizeDO transToActivityPrizeDO(CreatePrizeByActivityRequest param, Long activityID) {
        if (null == param) {
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_ERROR);
        }
        ActivityPrizeDO activityPrizeDO = new ActivityPrizeDO();
        BeanUtils.copyProperties(param, activityPrizeDO);
        activityPrizeDO.setActivityId(activityID);
        activityPrizeDO.setStatus(ActivityPrizeStatusEnum.INIT.name());
        return activityPrizeDO;
    }

    /**
     * @return ActivityUserDO
     */
    public static ActivityUserDO transToActivityUserDO(CreateUserByActivityRequest param, Long activityID) {
        if (null == param) {
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_USER_ERROR);
        }
        ActivityUserDO activityUserDO = new ActivityUserDO();
        BeanUtils.copyProperties(param, activityUserDO);
        activityUserDO.setActivityId(activityID);
        activityUserDO.setStatus(ActivityUserStatusEnum.INIT.name());
        return activityUserDO;
    }

    /**
     * @return ActivityDetailDTO
     */
    public static ActivityDetailDTO transToActivityDetailDTO(ActivityDO activityDO, List<PrizeDO> prizeDOS,
                                                             List<ActivityUserDO> users, List<ActivityPrizeDO> prizes) {
        if (null == activityDO || null == prizeDOS || null == users || null == prizes) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR);
        }
        ActivityDetailDTO activityDetailDTO = new ActivityDetailDTO();
        BeanUtils.copyProperties(activityDO, activityDetailDTO);
        activityDetailDTO.setActivityId(activityDO.getId());
        activityDetailDTO.setStatus(ActivityStatusEnum.forName(activityDO.getStatus()));

        activityDetailDTO.setPrizeDTOList(prizes.stream()
                .map(item -> BeanTransUtil.transToActivityPrizeDTO(item, prizeDOS))
                .toList());

        activityDetailDTO.setUserDTOList(users.stream()
                .map(BeanTransUtil::transToActivityUserDTO)
                .toList());

        return activityDetailDTO;
    }
    /**
     * @return ActivityUserDTO
     */
    private static ActivityUserDTO transToActivityUserDTO(ActivityUserDO activityUserDO) {
        if (null == activityUserDO) {
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_USER_ERROR);
        }
        ActivityUserDTO activityUserDTO = new ActivityUserDTO();
        BeanUtils.copyProperties(activityUserDO, activityUserDTO);
        activityUserDTO.setStatus(ActivityUserStatusEnum.forName(activityUserDO.getStatus()));
        return activityUserDTO;
    }

    /**
     * @return ActivityPrizeDTO
     */
    private static ActivityPrizeDTO transToActivityPrizeDTO(ActivityPrizeDO activityPrizeDO, List<PrizeDO> prizeDOS) {
        if (null == activityPrizeDO) {
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_ERROR);
        }
        ActivityPrizeDTO activityPrizeDTO = new ActivityPrizeDTO();

        Optional<PrizeDO> prizeDOOptional = prizeDOS.stream().
                filter(item -> item.getId().equals(activityPrizeDO.getPrizeId()))
                .findFirst();
        // ! 如果PrizeDO 为空，不执行当前方法，不为空才执行
        prizeDOOptional.ifPresent(prizeDO -> BeanUtils.copyProperties(prizeDO, activityPrizeDTO));

        BeanUtils.copyProperties(activityPrizeDO, activityPrizeDTO);
        activityPrizeDTO.setTiers(ActivityPrizeTiersEnum.forName(activityPrizeDO.getPrizeTiers()));
        activityPrizeDTO.setStatus(ActivityPrizeStatusEnum.forName(activityPrizeDO.getStatus()));

        return activityPrizeDTO;
    }

    /**
     * @return ActivityListResponse
     */
    public static ActivityListResponse transToActivityListResponse(PageListDTO<ActivityDTO> pageListDTO) {
        if (null == pageListDTO) {
            throw new ControllerException(ControllerErrorCodeConstants.FIND_ACTIVITY_LIST_ERROR);
        }
        ActivityListResponse activityListResponse = new ActivityListResponse();
        activityListResponse.setTotal(pageListDTO.getTotal());
        activityListResponse.setRecords(pageListDTO.getRecords()
                .stream()
                .map(BeanTransUtil::transToActivityInfo)
                .toList());
        return activityListResponse;
    }

    /**
     * @return ActivityListResponse.ActivityInfo
     */
    private static ActivityListResponse.ActivityInfo transToActivityInfo(ActivityDTO activityDTO) {
        if (null == activityDTO) {
            throw new ControllerException(ControllerErrorCodeConstants.FIND_ACTIVITY_LIST_ERROR);
        }
        ActivityListResponse.ActivityInfo activityInfo = new ActivityListResponse.ActivityInfo();
        BeanUtils.copyProperties(activityDTO, activityInfo);
        activityInfo.setValid(activityDTO.valid());
        return activityInfo;
    }

    /**
     * @return ActivityDTO
     */
    public static ActivityDTO transToActivityDTO(ActivityDO activityDO) {
        if (null == activityDO) {
            throw new ServiceException(ServiceErrorCodeConstants.CREATE_ACTIVITY_INFO_IS_EMPTY);
        }
        ActivityDTO activityDTO = new ActivityDTO();
        BeanUtils.copyProperties(activityDO, activityDTO);
        activityDTO.setActivityId(activityDO.getId());
        activityDTO.setStatus(ActivityStatusEnum.forName(activityDO.getStatus()));
        return activityDTO;
    }

    /**
     * @return ActivityDetailResponse
     */
    public static ActivityDetailResponse transToActivityDetailResponse(ActivityDetailDTO activityDetailDTO) {
        if (null == activityDetailDTO) {
            throw new ControllerException(ControllerErrorCodeConstants.GET_ACTIVITY_DETAIL_ERROR);
        }
        ActivityDetailResponse activityDetailResponse = new ActivityDetailResponse();
        BeanUtils.copyProperties(activityDetailDTO, activityDetailResponse);
        activityDetailResponse.setValid(activityDetailDTO.valid());

        activityDetailResponse.setPrizes(activityDetailDTO.getPrizeDTOList()
                .stream()
                .sorted(Comparator.comparingInt(activityPrizeDTO -> activityPrizeDTO.getTiers().getCode()))
                .map(BeanTransUtil::transToActivityPrizeResponse)
                .toList());

        activityDetailResponse.setUsers(activityDetailDTO.getUserDTOList()
                .stream()
                .map(BeanTransUtil::transToActivityUserResponse)
                .toList());

        return activityDetailResponse;
    }

    /**
     * @return ActivityUserResponse
     */
    private static ActivityUserResponse transToActivityUserResponse(ActivityUserDTO activityUserDTO) {
        if (null == activityUserDTO) {
            throw new ControllerException(ControllerErrorCodeConstants.GET_ACTIVITY_DETAIL_ERROR);
        }
        ActivityUserResponse activityUserResponse = new ActivityUserResponse();
        BeanUtils.copyProperties(activityUserDTO, activityUserResponse);
        activityUserResponse.setValid(activityUserDTO.valid());
        return activityUserResponse;
    }

    /**
     * @return ActivityPrizeResponse
     */
    private static ActivityPrizeResponse transToActivityPrizeResponse(ActivityPrizeDTO activityPrizeDTO) {
        if (null == activityPrizeDTO) {
            throw new ControllerException(ControllerErrorCodeConstants.GET_ACTIVITY_DETAIL_ERROR);
        }
        ActivityPrizeResponse activityPrizeResponse = new ActivityPrizeResponse();
        BeanUtils.copyProperties(activityPrizeDTO, activityPrizeResponse);
        activityPrizeResponse.setPrizeTierName(activityPrizeDTO.getTiers().getMessage());
        activityPrizeResponse.setValid(activityPrizeDTO.valid());
        return activityPrizeResponse;
    }

    /**
     * @return ConvertActivityStatusDTO
     */
    public static ConvertActivityStatusDTO transToConvertActivityStatusDTO(DrawPrizeRequest drawPrizeRequest, int condition) {
        if (null == drawPrizeRequest || (condition != 1 && condition != 2)) {
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_STATUS_CONVERT_ERROR);
        }
        // ! condition 为 1 时表示将状态扭转为 COMPLETED，为 2 时表示回滚状态
        ConvertActivityStatusDTO convertActivityStatusDTO = new ConvertActivityStatusDTO();
        BeanUtils.copyProperties(drawPrizeRequest, convertActivityStatusDTO);
        if (condition == 1) {
            convertActivityStatusDTO.setTargetActivityStatus(ActivityStatusEnum.COMPLETED);
            convertActivityStatusDTO.setTargetPrizeStatus(ActivityPrizeStatusEnum.COMPLETED);
            convertActivityStatusDTO.setTargetUserStatus(ActivityUserStatusEnum.COMPLETED);
        } else {
            convertActivityStatusDTO.setTargetActivityStatus(ActivityStatusEnum.RUNNING);
            convertActivityStatusDTO.setTargetPrizeStatus(ActivityPrizeStatusEnum.INIT);
            convertActivityStatusDTO.setTargetUserStatus(ActivityUserStatusEnum.INIT);
        }
        convertActivityStatusDTO.setUserIds(drawPrizeRequest.getWinnerList()
                .stream()
                .map(DrawPrizeRequest.Winner::getUserId)
                .toList());
        return convertActivityStatusDTO;
    }

    /**
     * @return WinningRecordDO
     */
    public static WinningRecordDO transToWinningRecordDO(ActivityDO activityDO, UserDO userDO, PrizeDO prizeDO, ActivityPrizeDO activityPrizeDO, Date winningTime) {
        if (null == activityDO || null == userDO
                || null == prizeDO || null == activityPrizeDO) {
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_IS_EMPTY);
        }
        WinningRecordDO winningRecordDO = new WinningRecordDO();
        winningRecordDO.setActivityId(activityDO.getId());
        winningRecordDO.setActivityName(activityDO.getActivityName());
        winningRecordDO.setPrizeId(prizeDO.getId());
        winningRecordDO.setPrizeName(prizeDO.getName());
        winningRecordDO.setPrizeTier(activityPrizeDO.getPrizeTiers());
        winningRecordDO.setWinnerId(userDO.getId());
        winningRecordDO.setWinnerName(userDO.getUserName());
        winningRecordDO.setWinnerEmail(userDO.getEmail());
        winningRecordDO.setWinnerPhoneNumber(userDO.getPhoneNumber());
        winningRecordDO.setWinningTime(winningTime);
        return winningRecordDO;
    }

    /**
     * @return WinningRecordsResponse
     */
    public static WinningRecordsResponse transToWinningRecordsResponse(WinningRecordsDTO winningRecordsDTO) {
        if (null == winningRecordsDTO) {
            throw new ControllerException(ControllerErrorCodeConstants.WINNING_RECORDS_IS_EMPTY);
        }
        WinningRecordsResponse winningRecordsResponse = new WinningRecordsResponse();
        BeanUtils.copyProperties(winningRecordsDTO, winningRecordsResponse);
        winningRecordsResponse.setPrizeTier(winningRecordsDTO.getPrizeTier().getMessage());
        return winningRecordsResponse;
    }

    /**
     * @return WinningRecordsDTO
     */
    public static WinningRecordsDTO transToWinningRecordsDTO(WinningRecordDO winningRecordDO) {
        if (null == winningRecordDO) {
            throw new ServiceException(ServiceErrorCodeConstants.WINNING_RECORDS_IS_EMPTY);
        }
        WinningRecordsDTO winningRecordsDTO = new WinningRecordsDTO();
        BeanUtils.copyProperties(winningRecordDO, winningRecordsDTO);
        winningRecordsDTO.setPrizeTier(ActivityPrizeTiersEnum.forName(
                winningRecordDO.getPrizeTier()
        ));
        return winningRecordsDTO;
    }
}
